#pragma once
#include "PDTStatement.h"
#include "PDTVar.h"
#include "PDTExp.h"
#include "PDTAssignment.h"
#include "PDTCondition.h"

class PDTBehaviors  :  public PDTStatement, public TraverseIfc <PDTBehaviors , PDTNode> { 
    public:  TRAVERSAL_IFC_IMPL(PDTBehaviors)
private:
	string name;
	int goodSize;
	int badSize;
public:
	PDTBehaviors(PDTCodeGraph& CG, string& aName, vector <PDTBehavior *> &aGood, vector <PDTBehavior *> &aBad):
		PDTStatement(CG), name(aName) {
		goodSize = aGood.size();
		badSize = aBad.size();

		PDTNode * goodNode;
		for (int i = 0; i < goodSize; i++) {
			goodNode = aGood[i];
			addChild(goodNode);
			goodNode->addParent(this);
		}

		PDTNode * badNode;
		for (int j = 0; j < badSize; j++) {
			badNode = aBad[j];
			addChild(badNode);
			badNode->addParent(this);
		}
	}

	NodeTypeEnum getType() {
		return PDTBehavior_Em;
	}

	virtual bool isBehaviors() const {
		return true;
	}

    virtual unsigned int getNumBehaviors() const {
        return goodSize+badSize;
    }

    virtual PDTBehavior* getBehavior(unsigned int i) const {
        assert (i < getNumBehaviors());
        return dynamic_cast<PDTBehavior*>(children[i]);
    }

	vector <PDTBehavior*> & getGoodAssignments(vector <PDTBehavior*> & inVec) {
		PDTBehavior * assign;
		for (int i = 0; i < goodSize; i++) {
			assign = dynamic_cast<PDTBehavior*>(children[i]);
			inVec.push_back(assign);
		}
		return inVec;
	}

	vector <PDTBehavior*> & getBadAssignments(vector <PDTBehavior*> & outVec) {
		PDTBehavior * assign;
		for (int i = goodSize; i < goodSize + badSize; i++) {
			assign = dynamic_cast<PDTBehavior*>(children[i]);
			outVec.push_back(assign);
		}
		return outVec;
	}

	const string & getName() {
		return name;
	}

	int getGoodSize()
	{
		return goodSize;
	}

	int getBadSize()
	{
		return badSize;
	}

	virtual void assignGoodInput(PDTCodeGraph &CG, int goodBehaviorID) //Make the assignments
    {
		vector <PDTBehavior*> goodInputAssignments;
		goodInputAssignments = getGoodAssignments(goodInputAssignments);
		if (goodBehaviorID>=0 && goodBehaviorID<goodSize)
		{
			goodInputAssignments[goodBehaviorID]->evalInput(CG);
		}
		else
			cout<<"Good Behavior ID chosen is out of bounds"<<endl;

    }

	virtual void assignGoodOutput(PDTCodeGraph &CG, int goodBehaviorID) //Make the assignments
    {
		vector <PDTBehavior*> goodInputAssignments;
		goodInputAssignments = getGoodAssignments(goodInputAssignments);
		if (goodBehaviorID>=0 && goodBehaviorID<goodSize)
			goodInputAssignments[goodBehaviorID]->evalOutput(CG);
		else
			cout<<"Good Behavior ID chosen is out of bounds"<<endl;

    }

	virtual void assignBadInput(PDTCodeGraph &CG, int badBehaviorID) //Make the assignments
    {
		vector <PDTBehavior*> badInputAssignments;
		badInputAssignments = getBadAssignments(badInputAssignments);
		if (badBehaviorID>=0 && badBehaviorID<goodSize)
			badInputAssignments[badBehaviorID]->evalInput(CG);
		else
			cout<<"Bad Behavior ID chosen is out of bounds"<<endl;

    }

	virtual void assignBadOutput(PDTCodeGraph &CG, int badBehaviorID) //Make the assignments
    {
		vector <PDTBehavior*> badInputAssignments;
		badInputAssignments = getBadAssignments(badInputAssignments);
		if (badBehaviorID>=0 && badBehaviorID<goodSize)
			badInputAssignments[badBehaviorID]->evalOutput(CG);
		else
			cout<<"Bad Behavior ID chosen is out of bounds"<<endl;

    }

	virtual stringstream & toString(stringstream & ss) const {
		ss << "@behavior " << name << " {\n";
		for (int i = 0; i < goodSize + badSize; i++) {
			children[i]->toString(ss);
			ss << "\n";
		}
		ss << "}\n";
		return ss;
	}
};
